{
 "cells": [
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:11.888180Z",
     "start_time": "2025-03-19T05:30:52.159494Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 2.0.2\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.1\n",
      "torch 2.6.0+cu126\n",
      "cuda:0\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 准备数据"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:34.074102Z",
     "start_time": "2025-03-19T05:31:25.935012Z"
    }
   },
   "source": [
    "from tensorflow import keras\n",
    "#用karas有的数据集imdb，电影分类,分电影是积极的，还是消极的\n",
    "imdb = keras.datasets.imdb\n",
    "#载入数据使用下面两个参数\n",
    "vocab_size = 10000  #词典大小，仅保留训练数据中前10000个最经常出现的单词，低频单词被舍弃\n",
    "index_from = 3  #0,1,2,3空出来做别的事\n",
    "#前一万个词出现词频最高的会保留下来进行处理，后面的作为特殊字符处理，\n",
    "# 小于3的id都是特殊字符，下面代码有写\n",
    "# 需要注意的一点是取出来的词表还是从1开始的，需要做处理\n",
    "(train_data, train_labels), (test_data, test_labels) = imdb.load_data(\n",
    "    num_words = vocab_size, index_from = index_from)"
   ],
   "outputs": [],
   "execution_count": 2
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:34.078399Z",
     "start_time": "2025-03-19T05:31:34.075100Z"
    }
   },
   "source": [
    "\n",
    "print(\"train\", len(train_data), train_labels.shape)  #25000个样本，每个样本是一段话，每个单词用一个数字表示\n",
    "print(\"test\", len(test_data), test_labels.shape)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train 25000 (25000,)\n",
      "test 25000 (25000,)\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:34.134665Z",
     "start_time": "2025-03-19T05:31:34.078399Z"
    }
   },
   "source": [
    "#载入词表，看下词表长度，词表就像英语字典\n",
    "word_index = imdb.get_word_index()\n",
    "print(len(word_index))\n",
    "print(type(word_index))\n",
    "#词表虽然有8万多，但是我们只载入了最高频的1万词！！！！"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "88584\n",
      "<class 'dict'>\n"
     ]
    }
   ],
   "execution_count": 4
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构造 word2idx 和 idx2word"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:34.170922Z",
     "start_time": "2025-03-19T05:31:34.135660Z"
    }
   },
   "source": [
    "word2idx = {word: idx + 3 for word, idx in word_index.items()}\n",
    "word2idx.update({\n",
    "    \"[PAD]\": 0,     # 填充 token\n",
    "    \"[BOS]\": 1,     # begin of sentence\n",
    "    \"[UNK]\": 2,     # 未知 token\n",
    "    \"[EOS]\": 3,     # end of sentence\n",
    "})\n",
    "\n",
    "idx2word = {idx: word for word, idx in word2idx.items()}"
   ],
   "outputs": [],
   "execution_count": 5
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:35.206872Z",
     "start_time": "2025-03-19T05:31:34.171918Z"
    }
   },
   "source": [
    "# 选择 max_length\n",
    "length_collect = {}\n",
    "for text in train_data:\n",
    "    length = len(text)\n",
    "    length_collect[length] = length_collect.get(length, 0) + 1\n",
    "    \n",
    "MAX_LENGTH = 500\n",
    "plt.bar(length_collect.keys(), length_collect.values())\n",
    "plt.axvline(MAX_LENGTH, label=\"max length\", c=\"gray\", ls=\":\")\n",
    "plt.legend()\n",
    "plt.show()"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 6
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tokenizer"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:35.239227Z",
     "start_time": "2025-03-19T05:31:35.207870Z"
    }
   },
   "source": [
    "class Tokenizer:\n",
    "    def __init__(self, word2idx, idx2word, max_length=500, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx\n",
    "        self.idx2word = idx2word\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx\n",
    "        self.bos_idx = bos_idx\n",
    "        self.eos_idx = eos_idx\n",
    "        self.unk_idx = unk_idx\n",
    "    \n",
    "    def encode(self, text_list, padding_first=False):\n",
    "        \"\"\"如果padding_first == True，则padding加载前面，否则加载后面\"\"\"\n",
    "        max_length = min(self.max_length, 2 + max([len(text) for text in text_list]))\n",
    "        indices_list = []\n",
    "        for text in text_list:\n",
    "            indices = [self.bos_idx] + [self.word2idx.get(word, self.unk_idx) for word in text[:max_length-2]] + [self.eos_idx]\n",
    "            if padding_first:\n",
    "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
    "            else:\n",
    "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
    "            indices_list.append(indices)\n",
    "        return torch.tensor(indices_list)\n",
    "    \n",
    "    \n",
    "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            text = []\n",
    "            for index in indices:\n",
    "                word = self.idx2word.get(index, \"[UNK]\")\n",
    "                if remove_bos and word == \"[BOS]\":\n",
    "                    continue\n",
    "                if remove_eos and word == \"[EOS]\":\n",
    "                    break\n",
    "                if remove_pad and word == \"[PAD]\":\n",
    "                    break\n",
    "                text.append(word)\n",
    "            text_list.append(\" \".join(text) if not split else text)\n",
    "        return text_list\n",
    "    \n",
    "\n",
    "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word)\n",
    "raw_text = [\"hello world\".split(), \"tokenize text datas with batch\".split(), \"this is a test\".split()]\n",
    "indices = tokenizer.encode(raw_text, padding_first=True)\n",
    "decode_text = tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "print(\"raw text\")\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices\")\n",
    "for index in indices:\n",
    "    print(index)\n",
    "print(\"decode text\")\n",
    "for decode in decode_text:\n",
    "    print(decode)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text\n",
      "['hello', 'world']\n",
      "['tokenize', 'text', 'datas', 'with', 'batch']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices\n",
      "tensor([   0,    0,    0,    1, 4825,  182,    3])\n",
      "tensor([    1,     2,  3004,     2,    19, 19233,     3])\n",
      "tensor([   0,    1,   14,    9,    6, 2181,    3])\n",
      "decode text\n",
      "[PAD] [PAD] [PAD] [BOS] hello world [EOS]\n",
      "[BOS] [UNK] text [UNK] with batch [EOS]\n",
      "[PAD] [BOS] this is a test [EOS]\n"
     ]
    }
   ],
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:35.243697Z",
     "start_time": "2025-03-19T05:31:35.239736Z"
    }
   },
   "source": [
    "# 看看训练集的数据\n",
    "\n",
    "tokenizer.decode(train_data[:2], remove_bos=False, remove_eos=False, remove_pad=False)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[\"[BOS] this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert [UNK] is an amazing actor and now the same being director [UNK] father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for [UNK] and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also [UNK] to the two little boy's that played the [UNK] of norman and paul they were just brilliant children are often left out of the [UNK] list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all\",\n",
       " \"[BOS] big hair big boobs bad music and a giant safety pin these are the words to best describe this terrible movie i love cheesy horror movies and i've seen hundreds but this had got to be on of the worst ever made the plot is paper thin and ridiculous the acting is an abomination the script is completely laughable the best is the end showdown with the cop and how he worked out who the killer is it's just so damn terribly written the clothes are sickening and funny in equal [UNK] the hair is big lots of boobs [UNK] men wear those cut [UNK] shirts that show off their [UNK] sickening that men actually wore them and the music is just [UNK] trash that plays over and over again in almost every scene there is trashy music boobs and [UNK] taking away bodies and the gym still doesn't close for [UNK] all joking aside this is a truly bad film whose only charm is to look back on the disaster that was the 80's and have a good old laugh at how bad everything was back then\"]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 8
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据集与 DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.751995Z",
     "start_time": "2025-03-19T05:31:35.243697Z"
    }
   },
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "class IMDBDataset(Dataset):\n",
    "    def __init__(self, data, labels, remain_length=True):\n",
    "        if remain_length:\n",
    "            self.data = tokenizer.decode(data, remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "        else:\n",
    "            # 缩减一下数据\n",
    "            self.data = tokenizer.decode(data)\n",
    "        self.labels = labels\n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        text = self.data[index]\n",
    "        label = self.labels[index]\n",
    "        return text, label\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self.data)\n",
    "    \n",
    "    \n",
    "def collate_fct(batch):\n",
    "    text_list = [item[0].split() for item in batch]\n",
    "    label_list = [item[1] for item in batch]\n",
    "    # 这里使用 padding first\n",
    "    text_list = tokenizer.encode(text_list, padding_first=True).to(dtype=torch.int)\n",
    "    return text_list, torch.tensor(label_list).reshape(-1, 1).to(dtype=torch.float)\n",
    "\n",
    "\n",
    "# 用RNN，缩短序列长度\n",
    "train_ds = IMDBDataset(train_data, train_labels, remain_length=False)\n",
    "test_ds = IMDBDataset(test_data, test_labels, remain_length=False)"
   ],
   "outputs": [],
   "execution_count": 9
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.756480Z",
     "start_time": "2025-03-19T05:31:36.752991Z"
    }
   },
   "source": [
    "batch_size = 128\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, collate_fn=collate_fct)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, collate_fn=collate_fct)"
   ],
   "outputs": [],
   "execution_count": 10
  },
  {
   "cell_type": "code",
   "source": [
    "for text, label in train_dl: #检查样本是否存在问题\n",
    "    print(text.shape, label.shape)\n",
    "    break"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.798079Z",
     "start_time": "2025-03-19T05:31:36.757475Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([128, 500]) torch.Size([128, 1])\n"
     ]
    }
   ],
   "execution_count": 11
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.812646Z",
     "start_time": "2025-03-19T05:31:36.798079Z"
    }
   },
   "source": [
    "class LSTM(nn.Module):\n",
    "    def __init__(self, embedding_dim=16, hidden_dim=64, vocab_size=vocab_size, num_layers=1, bidirectional=False):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.embeding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True, bidirectional=bidirectional)\n",
    "        self.layer = nn.Linear(hidden_dim * (2 if bidirectional else 1), hidden_dim)\n",
    "        self.fc = nn.Linear(hidden_dim, 1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        # [bs, seq length]\n",
    "        x = self.embeding(x)\n",
    "        # [bs, seq length, embedding_dim] -> shape [bs, seq length，hidden_dim]\n",
    "        seq_output, (hidden, cell) = self.lstm(x)\n",
    "        # print(f'seq_output.shape{seq_output.shape}')\n",
    "        # print(f'hidden.shape{hidden.shape}') #最后一个时间步的输出\n",
    "        # print(f'cell.shape{cell.shape}') #最后一个时间步的cell state\n",
    "        # print(seq_output[:, -1, :].squeeze()==hidden.squeeze()) #squeeze() 去掉轴的尺寸为1的哪个轴\n",
    "        # print(seq_output[:, -1, :].squeeze()==cell.squeeze())\n",
    "        x = seq_output[:, -1, :]\n",
    "        # 取最后一个时间步的输出 (这也是为什么要设置padding_first=True的原因)\n",
    "        x = self.layer(x)\n",
    "        x = self.fc(x)\n",
    "        return x\n",
    "    \n",
    "sample_inputs = torch.randint(0, vocab_size, (2, 128))\n",
    "    \n",
    "print(\"{:=^80}\".format(\" 一层单向 LSTM \"))       \n",
    "for key, value in LSTM().named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 一层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "execution_count": 12
  },
  {
   "cell_type": "code",
   "source": [
    "model = LSTM()\n",
    "#随机一个（128,500）的输入\n",
    "sample_inputs = torch.randint(0, vocab_size, (128, 500))\n",
    "sample_outputs = model(sample_inputs)\n",
    "print(sample_outputs.shape)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.908632Z",
     "start_time": "2025-03-19T05:31:36.813594Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([128, 1])\n"
     ]
    }
   ],
   "execution_count": 13
  },
  {
   "cell_type": "code",
   "source": [
    "64*64"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.912790Z",
     "start_time": "2025-03-19T05:31:36.909630Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4096"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 14
  },
  {
   "cell_type": "code",
   "source": [
    "4 * 16 * 64 #lstm.weight_ih_l0"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.916695Z",
     "start_time": "2025-03-19T05:31:36.913788Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4096"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 15
  },
  {
   "cell_type": "code",
   "source": [
    "128*64"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.921401Z",
     "start_time": "2025-03-19T05:31:36.917687Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8192"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 16
  },
  {
   "cell_type": "code",
   "source": [
    "print(\"{:=^80}\".format(\" 一层双向 LSTM \"))\n",
    "for key, value in LSTM(bidirectional=True).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.927254Z",
     "start_time": "2025-03-19T05:31:36.922398Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 一层双向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "       lstm.weight_ih_l0_reverse        paramerters num: 4096\n",
      "       lstm.weight_hh_l0_reverse        paramerters num: 16384\n",
      "        lstm.bias_ih_l0_reverse         paramerters num: 256\n",
      "        lstm.bias_hh_l0_reverse         paramerters num: 256\n",
      "              layer.weight              paramerters num: 8192\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "execution_count": 17
  },
  {
   "cell_type": "code",
   "source": [
    "print(\"{:=^80}\".format(\" 两层单向 LSTM \"))\n",
    "for key, value in LSTM(num_layers=2).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.932109Z",
     "start_time": "2025-03-19T05:31:36.927254Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 两层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 160000\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "           lstm.weight_ih_l1            paramerters num: 16384\n",
      "           lstm.weight_hh_l1            paramerters num: 16384\n",
      "            lstm.bias_ih_l1             paramerters num: 256\n",
      "            lstm.bias_hh_l1             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "execution_count": 18
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.936163Z",
     "start_time": "2025-03-19T05:31:36.932109Z"
    }
   },
   "cell_type": "code",
   "source": "16*64*4 #4是4倍",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4096"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 19
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:36.940160Z",
     "start_time": "2025-03-19T05:31:36.937160Z"
    }
   },
   "cell_type": "code",
   "source": "64*64*4",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "16384"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 20
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:37.343226Z",
     "start_time": "2025-03-19T05:31:36.941160Z"
    }
   },
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        # 二分类\n",
    "        preds = logits > 0\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ],
   "outputs": [],
   "execution_count": 21
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 可视化\n",
    "\n",
    "\n",
    "训练过程中可以使用如下命令启动tensorboard服务。\n",
    "\n",
    "```shell\n",
    "tensorboard \\\n",
    "    --logdir=runs \\     # log 存放路径\n",
    "    --host 0.0.0.0 \\    # ip\n",
    "    --port 8848         # 端口\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:37.507730Z",
     "start_time": "2025-03-19T05:31:37.343226Z"
    }
   },
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ],
   "outputs": [],
   "execution_count": 22
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:37.512459Z",
     "start_time": "2025-03-19T05:31:37.508726Z"
    }
   },
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": 23
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:31:37.516946Z",
     "start_time": "2025-03-19T05:31:37.513453Z"
    }
   },
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "outputs": [],
   "execution_count": 24
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:34:21.804981Z",
     "start_time": "2025-03-19T05:31:37.517944Z"
    }
   },
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits > 0\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 20\n",
    "\n",
    "model = LSTM()\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失 (但是二分类)\n",
    "loss_fct = F.binary_cross_entropy_with_logits\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/imdb-lstm\")\n",
    "# tensorboard_callback.draw_model(model, [1, MAX_LENGTH])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/imdb-lstm\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=10)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    test_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/3920 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "434962fec4a44f7da3a76f4a93756cc5"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 25
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:34:21.968788Z",
     "start_time": "2025-03-19T05:34:21.804981Z"
    }
   },
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 26
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-19T05:34:25.461262Z",
     "start_time": "2025-03-19T05:34:21.969783Z"
    }
   },
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/imdb-lstm/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, test_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.3773\n",
      "accuracy: 0.8649\n"
     ]
    }
   ],
   "execution_count": 27
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
